#include "../include/Db.h"
#include "../include/exception/DbException.h"

namespace ZY {

    void Db::Init()
    {
        if ( ! status[0] ) {
            mysql_init( & link );
            status[0] = 1;
            _result = NULL;
        }
    }

    Db::Db()
    {
        //ctor

    }

    Db::~Db()
    {
        //dtor
        if ( _result ) {
            delete _result;
        }
    }


    Db &Db::Connect()
    {
        Init();

        Close();

        #if MYSQL_VERSION_ID >= 50013
        my_bool reconnect = 1;

        if ( mysql_options( & link , MYSQL_OPT_RECONNECT, &reconnect) != 0) {
            string msg( "MYSQL_OPT_RECONNECT Set Error! ERROR:" );
            msg.append( mysql_error( & link ) );
            throw DbException( msg.c_str() , 20010 );
        }

        if ( mysql_options( & link , MYSQL_SET_CHARSET_NAME, "utf8") != 0 ) {
            string msg( "MYSQL_SET_CHARSET_NAME Set Error! ERROR:" );
            msg.append( mysql_error( & link ) );
            throw DbException( msg , 20011 );
        }

        #endif

        if ( ! mysql_real_connect( &link , _ip.c_str() , _user.c_str() , _pwd.c_str() , _dbname.c_str() , _port ,  NULL , CLIENT_MULTI_STATEMENTS) ) {
            char buff[4096];
            sprintf( buff , "MySQL Connect Failed!ip:%s port:%d user:%s dbname:%s ERROR:%s"   ,  _ip.c_str() , _port , _user.c_str() , _dbname.c_str() , mysql_error( & link ) );

            throw DbException ( (char*) buff , 20001 );;
        }

        status[1] = 1;

        return *this;
    }

    Db &Db::Connect( const string &ip , const unsigned short port , const string &user , const string &pwd )
    {
        setConnectInfo( ip , user , pwd , port );
        return Connect();
    }


    Db &Db::setConnectInfo( const string &ip , const string &user , const string &pwd )
    {
        return setConnectInfo( ip , user , pwd , 3306 );
    }
    Db &Db::setConnectInfo( const string &ip , const string &user , const string &pwd , unsigned short port )
    {
        _ip = ip;
        _port = port;
        _user = user;
        _pwd = pwd;
        return *this;
    }

    Db &Db::setConnectInfo( const string &ip , const string &user , const string &pwd , const string &dbname )
    {
        return setConnectInfo( ip , user , pwd , dbname , 0 );
    }

    Db &Db::setConnectInfo( const string &ip , const string &user , const string &pwd , const string &dbname , const unsigned short port  )
    {
        _ip = ip;
        _port = port;
        _user = user;
        _pwd = pwd;
        _dbname = dbname;

        return *this;
    }

    Db &Db::Connect( const string &ip , const unsigned short port , const string &user , const string &pwd , const string &dbname )
    {
        _dbname = dbname;
        return Connect( ip , port , user , pwd );
    }

    void Db::Close()
    {
        if ( status[1] ) {
            mysql_close( & link );
            status[1] = 0;
        }
    }

    Db & Db::Query( SQL &sql )
    {
        string sqlStr;
        sqlStr = sql.getSQL( *this );
        return Query( sqlStr );
    }

    Db & Db::Query( const string & sql )
    {
        int ret;
        if ( 0 == ( ret = mysql_real_query( & link , sql.c_str() , sql.length() ) ) ) {
            return *this;
        } else {
            const char *msg = mysql_error( &link );
            char buff[1024];
            sprintf( buff , "Query Failed!Error:%s" , msg );
            throw DbException( buff , 20002 , ret );
        }
    }


    DbResult *Db::QueryResult( SQL &sql )
    {
        string sqlStr;
        sqlStr = sql.getSQL( *this );
        return QueryResult( sqlStr );
    }

    DbResult *Db::QueryResult( const string &sql )
    {
        Query( sql );

        MYSQL_RES *res;

        res = mysql_store_result( & link );

        if ( ! res ) {
            throw DbException( "mysql_store_result exec failed!" , 20003 , mysql_errno(&link) );
        }

        return new DbResult( res );
    }

    void Db::QueryResultFree( const DbResult * dbr )
    {
        delete dbr;
    }

    int Db::GetInsertId()
    {
        return mysql_insert_id( &link );
    }

    int Db::GetAffectedRows()
    {
        return mysql_affected_rows( &link );
    }

    int Db::GetNumRows( const DbResult *res )
    {
        if ( res ) {
            return mysql_num_rows( res->_res );
        } else {
            throw DbException( "DbResult Pointer is NULL!" , 20005 );
        }
    }

    bool Db::setAutoCommit(bool _value)
    {
        if(_value){
            return mysql_autocommit(&link , 1);
        }else{
            return mysql_autocommit(&link , 0);
        }
    }

    bool Db::beginTransaction()
    {
        string transStr("begin");
        try{
            Query(transStr);
            return true;
        }catch(Exception e){
            return false;
        }
    }

    bool Db::commit()
    {
        string commitStr("commit");
        try{
            Query(commitStr);
            return true;
        }catch(Exception e){
            return false;
        }
    }

    bool Db::rollBack()
    {
        string rollBackStr("rollback");
        try{
            Query(rollBackStr);
            return true;
        }catch(Exception e){
            return false;
        }

    }
}

